﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;

namespace BleachReader
{
    /// <summary>
    /// http://t.pcomic.com.cn
    /// </summary>
    class PComicSpider
    {
        private string name;
        private string root;
        private string urlPattern;
        private int latestChapter;

        private int counter404;

        public PComicSpider(string name, string root, string bleach)
        {
            this.name = name;
            this.root = Path.Combine(root, name);
            this.urlPattern = bleach.Split(',').First();
            this.latestChapter = int.Parse(bleach.Split(',').Last());

            Log.Instance.WriteInfo("PComicSpider<{0}> initialized.", name);
            Log.Instance.WriteInfo("Root: {0}", root);
            Log.Instance.WriteInfo("URL: {0}", urlPattern);
            Log.Instance.WriteInfo("Chapter: {0}", latestChapter);
        }

        public void Run()
        {
            counter404 = 0;
            do
            {
                try
                {
                    new ChapterManager(latestChapter, root, urlPattern).DoWork();
                    counter404 = 0;
                }
                catch (WebException e)
                {
                    if (e.Status == WebExceptionStatus.ProtocolError)
                    {
                        var response = e.Response as HttpWebResponse;
                        if (response != null)
                        {
                            if (response.StatusCode == HttpStatusCode.NotFound)
                            {
                                //Log.Instance.WriteInfo("WebException->404: Chapter={0}, URL={1}", latestChapter, response.ResponseUri);
                            }
                            else
                            {
                                Log.Instance.WriteInfo("WebException->{2}[{3}]: Chapter={0}, URL={1}", latestChapter, response.ResponseUri, response.StatusCode, (int)response.StatusCode);
                            }
                        }
                    }
                    else
                    {
                        Log.Instance.WriteInfo("WebException->{2}: Chapter={0}, Msg={1}", latestChapter, e.Message, e.Status);
                    }
                    counter404++;
                }
                catch (Exception e)
                {
                    Log.Instance.WriteInfo("Exception->: Chapter={0}, Msg={1}", latestChapter, e.Message);
                    counter404++;
                }
            } while (latestChapter-- > 0 && counter404 < 3);

            Log.Instance.WriteInfo("Comic fechter exited, name={0}, chapter={1}, failure={2}", name, latestChapter, counter404);
        }
    }

    class ChapterManager
    {
        private int chapter;
        private string root;
        private string urlPattern;

        private IChapterFetcher fetcher = new ChapterFetcher();
        private IChapterStorage store = new ChapterStorage();

        private int page;
        private int counter404;

        public ChapterManager(int chapter, string root, string urlPattern)
        {
            // TODO: Complete member initialization
            this.chapter = chapter;
            this.root = root;
            this.urlPattern = urlPattern;

            page = 1;
            counter404 = 0;
        }

        public void DoWork()
        {
            try
            {
                GetOnePage();
                counter404 = 0;
            }
            catch (WebException)
            {
                throw;
            }
            catch (Exception e)
            {
                Log.Instance.WriteInfo("Exception->: Page={0}, Msg={1}", page, e.Message);
                counter404++;
            }

            while (counter404 < 3)
            {
                page++;

                try
                {
                    GetOnePage();
                    counter404 = 0;
                }
                catch (WebException e)
                {
                    if (e.Status == WebExceptionStatus.ProtocolError)
                    {
                        var response = e.Response as HttpWebResponse;
                        if (response != null)
                        {
                            if (response.StatusCode == HttpStatusCode.NotFound)
                            {
                                //Log.Instance.WriteInfo("WebException->404: Page={0}, URL={1}", page, response.ResponseUri);
                            }
                            else
                                Log.Instance.WriteInfo("WebException->{2}[{3}]: Page={0}, URL={1}", page, response.ResponseUri, response.StatusCode, (int)response.StatusCode);
                        }
                    }
                    else
                        Log.Instance.WriteInfo("WebException->{2}: Page={0}, Msg={1}", page, e.Message, e.Status);
                    counter404++;
                }
                catch (Exception e)
                {
                    Log.Instance.WriteInfo("Exception->: Page={0}, Msg={1}", page, e.Message);
                    counter404++;
                }
            }

            Log.Instance.WriteInfo("Chapter fechter exited, chapter={0}, failure={1}", chapter, counter404);
        }

        private void GetOnePage()
        {
            var target = urlPattern.Replace("@@@", chapter.ToString("000")).Replace("###", page.ToString("000"));
            var path = Path.Combine(root, chapter.ToString("000"));
            path = Path.Combine(path, string.Format("{0}.jpg", page.ToString("000")));

            var data = fetcher.Fetch(target);
            store.Save(path, data);
            Log.Instance.WriteInfo("{0} --> {1}", target, path);
        }
    }

    interface IChapterFetcher
    {
        byte[] Fetch(string url);
    }

    interface IChapterStorage
    {
        void Save(string path, byte[] data);
    }

    class ChapterFetcher : IChapterFetcher
    {
        public byte[] Fetch(string url)
        {
            using (var wc = new WebClient())
            {
                return wc.DownloadData(url);
            }
        }
    }

    class ChapterStorage : IChapterStorage
    {
        public void Save(string path, byte[] data)
        {
            EnsureDirectoryExist(path);
            File.WriteAllBytes(path, data);
        }

        private void EnsureDirectoryExist(string path)
        {
            var fi = new FileInfo(path);
            if (!fi.Directory.Exists)
                fi.Directory.Create();
        }
    }



}
